﻿using UnityEngine;
using System.Collections;
using System.IO;
using UnityEditor;

[ExecuteInEditMode]
public class VolcanoShader : MonoBehaviour {

    private static string _EditorResourcePath = "/FunctionShader/Sources/Shaders/Resources/";
    public string filename = "Function.shader";
    public GameObject DisplayObject;
    public Color MainColor;
    public Color LineColor;
    public Color WaterColor;
    public float LineWidth;
    public float WaterHeight;

    public float Height;
    public float Width;
    [Range(0,1)]public float Basin;
    public float Bumpiness;
    [Range(0,1)]public float Sharpness;
    public float InitialHeight;

    public bool UpdateFunction = false;

	// Use this for initialization
	void Start () {
        DisplayObject = this.gameObject;
	}

    void Update()
    {
        if(UpdateFunction)
        {
            UpdateShader();
            UpdateFunction = false;
        }
    }

    void UpdateShader()
    {
        string shader = LoadShaderFileToString();
        DisplayObject.renderer.sharedMaterial= WriteToFile(shader);
        DisplayObject.renderer.sharedMaterial.SetVector("_ColorMain", MainColor);
        DisplayObject.renderer.sharedMaterial.SetVector("_ColorLine", LineColor);
        DisplayObject.renderer.sharedMaterial.SetVector("_ColorWater", WaterColor);
        DisplayObject.renderer.sharedMaterial.SetFloat("_LineWidth", LineWidth);
        DisplayObject.renderer.sharedMaterial.SetFloat("_WaterHeight", WaterHeight - InitialHeight);
        DisplayObject.renderer.sharedMaterial.SetFloat("_WaterRange", Width);
    }

    string LoadShaderFileToString()
    {
        StreamReader sr = new StreamReader(Application.dataPath + _EditorResourcePath + filename);
        string line = sr.ReadToEnd();

        int pos = line.IndexOf("eqn =") + "eqn =".Length;

        //index of newLine
        int newLine = pos;
        bool found = false;
        while(!found)
        {
            newLine++;
            found = line[newLine] == ';';
        }

        float bs = Mathf.Min(.8f, -.2f + Mathf.Max(.1f, Basin + .1f));

        line = line.Remove(pos, newLine - pos);
        string equation1, equation2, equation3;
        equation1 = Height.ToString() + " * (pow(2, -1 * pow((x + " + Width.ToString() + ") / (" + (1.2 * Width * (1 - bs)).ToString() + " ), 2)) + ";
        equation2 = "pow(2, -1 * pow((x - " + Width.ToString() + ") / (" + (1.2 * Width * (1-bs)).ToString() + " ), 2))) + "; 
        equation3 =  Bumpiness.ToString() + " * (" + Sharpness.ToString() + " * (round(sin(x) + sin(.5 * x))) + (1 - " + Sharpness.ToString() + ") * (sin(x) + sin(.5 * x))) - " + InitialHeight.ToString();
        line = line.Insert(pos, equation1 + equation2 + equation3);

        return line;
    }

    Material WriteToFile(string shaderString)
    {
        Directory.CreateDirectory(Application.dataPath + _EditorResourcePath);
        File.WriteAllText(Application.dataPath + _EditorResourcePath + "/FunctionRuntime.shader", shaderString);
        Shader currentShader = Resources.Load("FunctionRuntime") as Shader;
        var path = AssetDatabase.GetAssetPath(currentShader);
        AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
        Material m = new Material(currentShader);
        return m;
    }
}
